Skip to content

Method: ListHandler(RepoConnection, ValueFactory)

1: /*
2: * JOPA
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.ontodriver.rdf4j.list;
19:
20: import cz.cvut.kbss.ontodriver.descriptor.ListDescriptor;
21: import cz.cvut.kbss.ontodriver.descriptor.ListValueDescriptor;
22: import cz.cvut.kbss.ontodriver.exception.IntegrityConstraintViolatedException;
23: import cz.cvut.kbss.ontodriver.rdf4j.connector.RepoConnection;
24: import cz.cvut.kbss.ontodriver.rdf4j.exception.Rdf4jDriverException;
25: import cz.cvut.kbss.ontodriver.rdf4j.util.Rdf4jUtils;
26: import org.eclipse.rdf4j.model.IRI;
27: import org.eclipse.rdf4j.model.Resource;
28: import org.eclipse.rdf4j.model.Statement;
29: import org.eclipse.rdf4j.model.Value;
30: import org.eclipse.rdf4j.model.ValueFactory;
31:
32: import java.util.ArrayList;
33: import java.util.Collection;
34: import java.util.Collections;
35: import java.util.List;
36: import java.util.Set;
37:
38: /**
39: * Base class for list handlers.
40: * <p>
41: * List handlers are responsible for loading and persisting lists.
42: */
43: abstract class ListHandler<VD extends ListValueDescriptor<?>> {
44:
45: final RepoConnection connector;
46: final ValueFactory vf;
47:
48: ListHandler(RepoConnection connector, ValueFactory vf) {
49: this.connector = connector;
50: this.vf = vf;
51: }
52:
53: /**
54: * Persists list values specified by the descriptor.
55: * <p>
56: * The values are saved in the order in which they appear in the descriptor.
57: *
58: * @param listValueDescriptor Describes values to persist
59: * @throws Rdf4jDriverException When storage access error occurs
60: */
61: public void persistList(VD listValueDescriptor) throws Rdf4jDriverException {
62: if (listValueDescriptor.getValues().isEmpty()) {
63: return;
64: }
65: final Collection<Statement> statements = new ArrayList<>(listValueDescriptor.getValues().size());
66: final IRI head = createListHead(listValueDescriptor, statements);
67: statements.addAll(createListRest(head, listValueDescriptor));
68: connector.addStatements(statements);
69: }
70:
71: protected abstract IRI createListHead(VD listValueDescriptor, Collection<Statement> listStatements) throws Rdf4jDriverException;
72:
73: protected abstract List<Statement> createListRest(IRI head, VD listValueDescriptor)throws Rdf4jDriverException;
74:
75: /**
76: * Updates list with values specified by the descriptor.
77: *
78: * @param listValueDescriptor Describes the updated values
79: * @throws Rdf4jDriverException When storage access error occurs
80: */
81: public void updateList(VD listValueDescriptor) throws Rdf4jDriverException {
82: if (listValueDescriptor.getValues().isEmpty()) {
83: clearList(listValueDescriptor);
84: } else if (isOldListEmpty(owner(listValueDescriptor), hasList(listValueDescriptor),
85: listValueDescriptor.getListProperty().isInferred(), contexts(listValueDescriptor))) {
86: persistList(listValueDescriptor);
87: } else {
88: mergeList(listValueDescriptor);
89: }
90: }
91:
92: protected abstract void clearList(VD listDescriptor) throws Rdf4jDriverException;
93:
94: protected abstract void mergeList(VD listDescriptor) throws Rdf4jDriverException;
95:
96: boolean isOldListEmpty(Resource owner, IRI hasListProperty, boolean includeInferred,
97: Set<IRI> contexts) throws Rdf4jDriverException {
98: final Collection<Statement> stmts = connector.findStatements(owner, hasListProperty, null,
99: includeInferred, contexts);
100: return stmts.isEmpty();
101: }
102:
103: void removeObsoletes(ListIterator<?> it) throws Rdf4jDriverException {
104: while (it.hasNext()) {
105: it.nextNode();
106: it.remove();
107: }
108: }
109:
110: Resource extractListNode(Collection<Statement> stmts, IRI nodeAssertion) {
111: if (stmts.size() > 1) {
112: throw new IntegrityConstraintViolatedException(
113: "Invalid number of values found for assertion " + nodeAssertion + ". Expected 1, got " +
114: stmts.size());
115: }
116: final Value val = stmts.iterator().next().getObject();
117: if (!(val instanceof Resource)) {
118: throw new IntegrityConstraintViolatedException(
119: "Invalid property value. Expected object property value, got literal.");
120: }
121: return (Resource) val;
122: }
123:
124: Set<IRI> contexts(ListDescriptor listDescriptor) {
125: final IRI ctx = toRdf4jIri(listDescriptor.getContext());
126: return ctx != null ? Collections.singleton(ctx) : Collections.emptySet();
127: }
128:
129: IRI context(ListDescriptor listDescriptor) {
130: return toRdf4jIri(listDescriptor.getContext());
131: }
132:
133: IRI owner(ListDescriptor listDescriptor) {
134: return toRdf4jIri(listDescriptor.getListOwner().getIdentifier());
135: }
136:
137: IRI hasList(ListDescriptor listDescriptor) {
138: return toRdf4jIri(listDescriptor.getListProperty().getIdentifier());
139: }
140:
141: IRI hasNext(ListDescriptor listDescriptor) {
142: return toRdf4jIri(listDescriptor.getNextNode().getIdentifier());
143: }
144:
145: IRI toRdf4jIri(java.net.URI uri) {
146: return Rdf4jUtils.toRdf4jIri(uri, vf);
147: }
148:
149:
150: static final class MergeResult {
151: final int i;
152: final Resource previous;
153:
154: MergeResult(int i, Resource node) {
155: this.i = i;
156: this.previous = node;
157: }
158: }
159: }